package ae.pcfc.etks.online.web.controller.user.management.manage;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Locale;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.validation.Valid;

import org.apache.commons.lang.RandomStringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.support.SessionStatus;
import org.springframework.web.servlet.support.RequestContextUtils;
import org.springframework.web.util.WebUtils;

import ae.pcfc.etks.online.common.ConstantsCommon;
import ae.pcfc.etks.online.common.delegate.SecretQuestionDelegate;
import ae.pcfc.etks.online.common.delegate.ServiceDelegate;
import ae.pcfc.etks.online.common.delegate.UserDelegate;
import ae.pcfc.etks.online.common.vo.ClientCompanyVO;
import ae.pcfc.etks.online.common.vo.ClientEmailVO;
import ae.pcfc.etks.online.common.vo.LabelVO;
import ae.pcfc.etks.online.common.vo.PagingVO;
import ae.pcfc.etks.online.common.vo.PasswordResetVO;
import ae.pcfc.etks.online.common.vo.SecretQuestionVO;
import ae.pcfc.etks.online.common.vo.ServiceVO;
import ae.pcfc.etks.online.common.vo.UserServiceVO;
import ae.pcfc.etks.online.common.vo.UserVO;
import ae.pcfc.etks.online.web.ConstantsAdmin;
import ae.pcfc.etks.online.web.PageType;
import ae.pcfc.etks.online.web.ViewPath;
import ae.pcfc.etks.online.web.ViewUtils;
import ae.pcfc.etks.online.web.common.Constants;
import ae.pcfc.etks.online.web.controller.BaseController;
import ae.pcfc.etks.online.web.model.CompanyEmployee;
import ae.pcfc.etks.online.web.model.JQGridJSONModel;
import ae.pcfc.etks.online.web.model.Service;
import ae.pcfc.etks.online.web.util.SecurityUtils;

/* $Id: UserManagementController 
 * Copyright (C) 2011, Trakhees
 *  
 *  History
 *
 * Date  			Author 					Remarks
 * -------------------------------------------------------------
 * Jan 4, 2012 	Ismail 	        Created
 *
 */

/**
 * Controller that handles all {@link UserManagementController}-related
 * requests, i.e.: all requests for /user/general/manage/*
 * 
 * @author Ismail
 */

@Controller
@RequestMapping(ViewPath.USER_MANAGE)
public class UserManagementController extends BaseController{

	private static Logger log = LoggerFactory
			.getLogger(UserManagementController.class);

	private UserDelegate userDelegate;

	@Resource(name = "userDelegate")
	public void setUserDelegate(UserDelegate userDelegate) {
		this.userDelegate = userDelegate;
	}

	private SecretQuestionDelegate secretQuestionDelegate;

	@Resource(name = "secretQuestionDelegate")
	public void setSecretQuestionDelegate(
			SecretQuestionDelegate secretQuestionDelegate) {
		this.secretQuestionDelegate = secretQuestionDelegate;
	}

	private ServiceDelegate serviceDelegate;

	@Resource(name = "serviceDelegate")
	public void setServiceDelegate(ServiceDelegate serviceDelegate) {
		this.serviceDelegate = serviceDelegate;

	}

	/**
	 * Custom handler for displaying the form, i.e.: GET requests for
	 * user/general/manage/list.jsp
	 * 
	 * @see WEB-INF/jsp/user/general/manage/list.jsp
	 */

	@RequestMapping(value = "/list.htm", method = RequestMethod.GET)
	public void list(
			@ModelAttribute(value = ConstantsAdmin.USER_LIST_MODEL_KEY) UserVO command) {

	}

	public ClientCompanyVO populateClientInfo() {
		Object principal = SecurityContextHolder.getContext()
				.getAuthentication().getPrincipal();
		String strUserName;
		if (principal instanceof UserDetails) {
			strUserName = ((UserDetails) principal).getUsername();
		} else {
			strUserName = principal.toString();
		}

		UserVO userVO = userDelegate.findUserByUserName(strUserName);

		ClientCompanyVO client = null;
		if (userVO != null) {
			client = userVO.getClient();
		}
		return client;
	}

	@ModelAttribute(ConstantsAdmin.USER_SECRETQUESTION_REQUEST_MODEL_KEY)
	public List<LabelVO> populateSecretQuestionList() {

		List<LabelVO> labelList = new ArrayList<LabelVO>();

		LabelVO labelVO;
		List<SecretQuestionVO> secretQuestionVOs = secretQuestionDelegate
				.getSecretQuestionList();

		for (SecretQuestionVO secretQuestionVO : secretQuestionVOs) {
			labelVO = getMapper().map(secretQuestionVO,
					LabelVO.class);
			labelList.add(labelVO);

		}
		return labelList;
	}

	@ModelAttribute(ConstantsAdmin.USER_ADMIN_USER_LOCK_MODEL_KEY)
	public List<LabelVO> populateActionList(Locale locale) {

		List<LabelVO> labelList = new ArrayList<LabelVO>();

		LabelVO labelVO = new LabelVO();
		labelVO.setId(Constants.ACTIVE);

		labelVO.setDisplayLabel(getMessageSource().getMessage("label.user.active",
				null, locale));

		labelList.add(labelVO);

		labelVO = new LabelVO();
		labelVO.setId(Constants.INACTIVE);
		labelVO.setDisplayLabel(getMessageSource().getMessage("label.user.inactive",
				null, locale));

		labelList.add(labelVO);

		return labelList;
	}


	public List<Service> getUserServiceList() {

		List<Service> serviceModels = new ArrayList<Service>();

		Object principal = SecurityContextHolder.getContext()
				.getAuthentication().getPrincipal();
		String strUserName = null;

		if (principal instanceof UserDetails) {
			strUserName = ((UserDetails) principal).getUsername();
		} else {
			strUserName = principal.toString();
		}

		List<ServiceVO> serviceVOs = this.serviceDelegate
				.findServiceListByUserName(strUserName);

		if (serviceVOs != null && serviceVOs.size() > 0) {
			Service service;
			for (ServiceVO serviceVO : serviceVOs) {
				service = new Service();
				getMapper().map(serviceVO, service);
				serviceModels.add(service);
			}
		}

		return serviceModels;
	}

	/**
	 * Custom handler for displaying the form, i.e.: GET requests for
	 * user/general/manage/form.jsp
	 * 
	 * @see WEB-INF/jsp/user/general/manage/form.jsp
	 */

	@RequestMapping(value = "/form.htm", method = RequestMethod.GET)
	public void add(
			@ModelAttribute(ConstantsAdmin.USER_PERSON_INFO_MODEL_KEY) CompanyEmployee model) {
		model.setStrStatus("A");
	}

	/**
	 * Custom handler for displaying the form, i.e.: POST requests for
	 * user/general/manage/form.jsp
	 * 
	 * @see WEB-INF/jsp/user/general/manage/form.jsp
	 */
	@RequestMapping(method = RequestMethod.POST, value = "/form.htm")
	public String form(
			HttpServletRequest request,
			HttpSession session,
			SessionStatus status,
			Model model,
			Locale locale,
			@ModelAttribute(ConstantsAdmin.USER_PERSON_INFO_MODEL_KEY) CompanyEmployee companyEmployee,
			BindingResult errors) throws Exception {

		UserVO userVO = new UserVO();
		getMapper().map(companyEmployee, userVO);
		Object principal = SecurityContextHolder.getContext()
				.getAuthentication().getPrincipal();
		String strUserName;
		if (principal instanceof UserDetails) {
			strUserName = ((UserDetails) principal).getUsername();
		} else {
			strUserName = principal.toString();
		}

		UserVO adminUserVO = userDelegate.findUserByUserName(strUserName);

		userVO.setStrClientType(adminUserVO.getStrClientType());
		userVO.setCreateDate(Calendar.getInstance().getTime());
		userVO.setStrType(Constants.EMPLOYEE);
		//userVO.setStrStatus(Constants.ACTIVE);

		userVO.setStrPassword(SecurityUtils.hashPassword(userVO
				.getStrPassword()));
		ClientCompanyVO client = populateClientInfo();
		userVO.setClient(client);

		List<ServiceVO> lServicesSelected = new ArrayList<ServiceVO>();
		for (Long lServiceId : companyEmployee.getArrServices()) {
			if (lServiceId != null) {
				ServiceVO serviceVO = serviceDelegate
						.getServiceByPrimaryKey(lServiceId);
				lServicesSelected.add(serviceVO);
			}
		}
		model.addAttribute(ConstantsAdmin.USER_ADMIN_ADD_SERVICE_LIST,
				lServicesSelected);
		UserServiceVO userServiceVO = new UserServiceVO();
		userServiceVO.setlServiceVO(companyEmployee.getArrServices());
		userServiceVO.setStrUserName(userVO.getStrUsrName());
		userServiceVO.setStrUserType(userVO.getStrType());

		serviceDelegate.registerEmployee(userVO, userServiceVO);
		session.setAttribute(ConstantsAdmin.SUCCESS_PARAM, getMessageSource().getMessage(
				"success.user.info.edit", null, locale));
		status.setComplete();
		return ViewUtils.getRedirect(ViewPath.USER_MANAGE, PageType.LIST);

	}

	/**
	 * Custom handler for displaying the form, i.e.: GET requests for
	 * user/general/manage/edit.jsp
	 * 
	 * @see WEB-INF/jsp/user/general/manage/edit.jsp
	 */
	@RequestMapping(value = "/edit.htm", method = RequestMethod.GET)
	public void edit(
			HttpServletRequest request,
			Model model,
			@RequestParam(value = "userId", required = true) String userId,
			@ModelAttribute(ConstantsAdmin.USER_PERSON_INFO_MODEL_KEY) CompanyEmployee companyEmployee,
			Locale locale) {

		UserVO userVO = this.userDelegate.findUserByPrimaryKey(Long
				.valueOf(SecurityUtils.decrypt(userId)));

		if (userVO != null) {
			// companyEmployee = new CompanyEmployee();
			getMapper().map(userVO, companyEmployee);

			// model.addAttribute(Constants.USER_PERSON_INFO_MODEL_KEY,
			// companyEmployee);
			List<ServiceVO> serviceVOs = this.serviceDelegate
					.findServiceListByUserName(companyEmployee.getStrUserName());
			List<Long> listServiceIds = new ArrayList<Long>();
			if (serviceVOs != null) {
				for (ServiceVO serviceVO : serviceVOs) {
					listServiceIds.add(serviceVO.getStrServiceID());
				}
			}

			companyEmployee.setArrServices(listServiceIds);
			List<Service> serviceModels = new ArrayList<Service>();
			if (serviceVOs != null && serviceVOs.size() > 0) {
				Service service;
				for (ServiceVO serviceVO : serviceVOs) {
					service = new Service();
					getMapper().map(serviceVO, service);
					serviceModels.add(service);
				}
			}
			model.addAttribute(ConstantsAdmin.USER_ADMIN_EDIT_SERVICE_LIST,
					serviceModels);
		}
	}

	/**
	 * Custom handler for displaying the form, i.e.:POST requests for
	 * WEB-INF/jsp/user/general/manage/edit.jsp
	 * 
	 * @see #form(Service)
	 * @see WEB-INF/jsp/user/general/manage/edit.jsp
	 */

	@RequestMapping(method = RequestMethod.POST, value = "/edit.htm")
	public String edit(
			HttpServletRequest request,
			Model model,
			HttpSession session,
			SessionStatus status,
			Locale locale,
			@ModelAttribute(value = ConstantsAdmin.USER_PERSON_INFO_MODEL_KEY) CompanyEmployee companyEmployee,
			BindingResult errors) {

		String[] messageArgs = new String[] { getMessageSource().getMessage(
				"success.user.info.edit", null,
				RequestContextUtils.getLocale(request)) };

		UserVO userVO = null;
		userVO = userDelegate.findUserByUserName(companyEmployee
				.getStrUserName());
		if (userVO == null) {
			return ViewUtils.DEFAULT_VIEW;
		}


		if (userVO.getStrType().equals(Constants.COMPANY_ONLINE_ADMIN)) {
			getMapper().map(userVO, companyEmployee);			
			List<ServiceVO> serviceVOs = this.serviceDelegate
					.findServiceListByUserName(companyEmployee.getStrUserName());
			List<Long> listServiceIds = new ArrayList<Long>();
			if (serviceVOs != null) {
				for (ServiceVO serviceVO : serviceVOs) {
					listServiceIds.add(serviceVO.getStrServiceID());
				}
			}

			companyEmployee.setArrServices(listServiceIds);
			List<Service> serviceModels = new ArrayList<Service>();
			if (serviceVOs != null && serviceVOs.size() > 0) {
				Service service;
				for (ServiceVO serviceVO : serviceVOs) {
					service = new Service();
					getMapper().map(serviceVO, service);
					serviceModels.add(service);
				}
			}
			model.addAttribute(ConstantsAdmin.USER_ADMIN_EDIT_SERVICE_LIST,
					serviceModels);

			errors.reject("error.user.admin.edit", messageArgs, null);
			return ViewUtils.DEFAULT_VIEW;
		}
		
		getMapper().map(companyEmployee, userVO);	
		List<ServiceVO> lServicesSelected = new ArrayList<ServiceVO>();
		for (Long lServiceId : companyEmployee.getArrServices()) {
			if (lServiceId != null) {
				ServiceVO serviceVO = serviceDelegate
						.getServiceByPrimaryKey(lServiceId);
				lServicesSelected.add(serviceVO);
			}
		}
		model.addAttribute(ConstantsAdmin.USER_ADMIN_EDIT_SERVICE_LIST,
				lServicesSelected);

		if(companyEmployee.getStrEmailNotification()==null){
			userVO.setStrEmailNotification(null);
		}
		if(companyEmployee.getStrMobileNotification()==null){
			userVO.setStrSmsNotification(null);
		}
		// userVO.setStrPassword(SecurityUtils.encodePassword(userVO
		// .getStrPassword()));
		ClientCompanyVO client = populateClientInfo();
		userVO.setClient(client);

		UserServiceVO userServiceVO = new UserServiceVO();
		userServiceVO.setlServiceVO(companyEmployee.getArrServices());
		userServiceVO.setStrUserName(userVO.getStrUsrName());
		userServiceVO.setStrUserType(userVO.getStrType());

		serviceDelegate.updateEmployee(userVO, userServiceVO);

		session.setAttribute(ConstantsAdmin.SUCCESS_PARAM, getMessageSource().getMessage(
				"success.user.info.edit", null, locale));

		status.setComplete();
		return ViewUtils.getRedirect(ViewPath.USER_MANAGE, PageType.LIST);
	}

	/**
	 * Custom handler for displaying the form, i.e.: GET & POST requests for
	 * user/general/manage/service/searchService
	 * 
	 * @see WEB-INF/jsp/user/general/manage/service/searchService
	 */
	@RequestMapping(value = "service/searchService")
	public String searchServiceTable(
			@RequestParam(value = "searchKey", required = true) String searchKey,
			Model model) {
		List<Service> lMatchedServices = new ArrayList<Service>();
		if (searchKey != null && StringUtils.hasText(searchKey)) {
			List<Service> serviceModels = getUserServiceList();
			for (Service service : serviceModels) {
				if (service.getStrServiceNameArb().toUpperCase()
						.startsWith(searchKey.toUpperCase())
						|| service.getStrServiceNameEng().toUpperCase()
								.startsWith(searchKey.toUpperCase())) {
					lMatchedServices.add(service);
				}
			}
		}
		model.addAttribute(ConstantsAdmin.USER_ADMIN_SERVICE_SEARCH_RESULT,
				lMatchedServices);
		return ViewUtils
				.getForward(ViewPath.USER_MANAGE_SERVICE, PageType.LIST);
	}

	/**
	 * Custom handler for displaying the form, i.e.: POST requests for
	 * user/general/manage/service/searchService
	 * 
	 * @see WEB-INF/jsp/user/general/manage/service/searchService
	 */
	@RequestMapping(method = RequestMethod.POST, value = "resetpassword")
	@ResponseBody
	public String resetPassword(
			@RequestParam(value = "userid", required = true) String encUserId,
			Locale locale) {
		Long lUserId = Long.valueOf(SecurityUtils.decrypt(encUserId));
		UserVO userVO = this.userDelegate.findUserByPrimaryKey(lUserId);

		if (userVO != null && userVO.getlUserId()!= null) {
			String strPassword = RandomStringUtils
					.randomAlphanumeric(ConstantsCommon.PASSWORD_RESET_DEFAULT_LENGTH);

			PasswordResetVO passwordResetVO = new PasswordResetVO();

			passwordResetVO.setStrEmail(userVO.getStrEmail());
			passwordResetVO.setlUserId(userVO.getlUserId());
			passwordResetVO.setStrPassword(SecurityUtils
					.hashPassword(strPassword));

			// Reseting the password to a default generated password
			this.userDelegate.resetPassword(passwordResetVO);

			ClientEmailVO clientEmailVO = new ClientEmailVO();

			clientEmailVO.setStrEmailAddress(userVO.getStrEmail());
			clientEmailVO.setStrEmailSubject(getMessageSource().getMessage(
					"msg.forgot.password.subject", null, locale));
			clientEmailVO.setStrEmailBody(getMessageSource().getMessage(
					"msg.forgot.password.body",
					new String[] { userVO.getStrUsrName(), strPassword },
					locale));
			this.userDelegate.getUserNameAndPassword(clientEmailVO);
			return getMessageSource().getMessage("user.reset.password.success",
					new Object[] { userVO.getStrUsrName() }, locale);

		}
		return getMessageSource().getMessage("error.client.username.not.found", null,
				locale);

	}

	@RequestMapping(value = "/displayUserTable")
	public @ResponseBody
	JQGridJSONModel displayServicesTable(
			HttpServletRequest request,
			@RequestParam(value = "page", required = true) String page,
			@RequestParam(value = "rows", required = true) String rows,
			@RequestParam(value = "sidx", required = true) String sidx,
			@RequestParam(value = "sord", required = true, defaultValue = "desc") String sord,
			@RequestParam(value = "_search", required = false) String isSearch,
			@RequestParam(value = "searchField", required = false) String searchField,
			@RequestParam(value = "searchOper", required = false) String searchOper,
			@RequestParam(value = "searchString", required = false) String searchString) {

		List<String> requestParameterNames = Collections
				.list((Enumeration<String>) request.getParameterNames());

		for (String parameterName : requestParameterNames) {
			System.out.println("parameterName = " + parameterName);

		}

		System.out.println("page==" + page);
		System.out.println("rows==" + rows);
		System.out.println("sidx==" + sidx);
		System.out.println("searchField==" + searchField);
		System.out.println("searchOper==" + searchOper);
		System.out.println("searchString==" + searchString);
		System.out.println("isSearch==" + isSearch);
		System.out.println("sord==" + sord);

		JQGridJSONModel result = new JQGridJSONModel();

		Integer pageIndx = 1, totalpages = 0, start = 0;
		Integer limit = 40;
		try {
			pageIndx = Integer.parseInt(page);
		} catch (Exception nullexp) {
			pageIndx = 1;
		}
		try {
			limit = Integer.parseInt(rows);
		} catch (Exception nullexp) {
			pageIndx = 10;
		}

		PagingVO pagingVO = new PagingVO();
		pagingVO.setStart(start);
		pagingVO.setSearchfieldName(searchField);
		pagingVO.setSerachString(searchString);
		pagingVO.setSortFieldName(sidx);
		pagingVO.setSortOrder(sord);
		//pagingVO.setPageNumber(pageIndx);
		//pagingVO.setPageSize(limit);
		ClientCompanyVO client = populateClientInfo();
		pagingVO.setClientId("" + client.getCId());

		List<UserVO> userVOs = this.userDelegate
				.getUserListByPagingParameters(pagingVO);

		Integer count = 0;
		if (userVOs != null) {
			count = userVOs.size();

			
			if (count > 0)
				totalpages = (int) Math.ceil(((float) count) / (float) limit);
			else
				totalpages = 0;

			if (pageIndx > totalpages)
				pageIndx = totalpages;

			start = (limit * pageIndx) - limit;
			result.setPage(pageIndx.toString());
			result.setRecords(count + "");
			result.setTotal(totalpages + "");
			log.info("Page=" + pageIndx + " , Records=" + limit + " , Total="
					+ totalpages);

			for (UserVO userVO : userVOs) {
				List<String> cells = new ArrayList<String>();
				cells.add(userVO.getlUserId().toString());
				cells.add(userVO.getStrUserName());
				cells.add(userVO.getStrUserNameArab());
				cells.add(userVO.getStrEmail());
				cells.add(userVO.getStrStatus().equals(Constants.ACTIVE) ? ConstantsAdmin.STATUS_ACTIVE
						: ConstantsAdmin.STATUS_INACTIVE);
				cells.add(SecurityUtils.encrypt(userVO.getlUserId().toString()));
				result.addRows(userVO.getlUserId().toString(), cells);
			}
		}

		return result;

	}

	/**
	 * Custom handler for displaying the form, i.e.:POST requests for
	 * user/general/manage/list.jsp
	 * 
	 * 
	 * @see WEB-INF/jsp/user/general/manage/list.jsp
	 */

	@RequestMapping(method = RequestMethod.POST, value = "/list.htm")
	public String list(
			HttpServletRequest request,
			SessionStatus status,
			@ModelAttribute(value = ConstantsAdmin.ADMIN_SHOW_SERVICE_MODEL_KEY) @Valid Service listService,
			BindingResult errors) {

		boolean isSave = WebUtils.hasSubmitParameter(request,
				ConstantsAdmin.SAVE_BUTTON);

		if (isSave) {
			if (errors.hasErrors()) {

				return ViewUtils.DEFAULT_VIEW;

			} else {

				String[] messageArgs = new String[] { getMessageSource().getMessage(
						"success.user.info.edit", null,
						RequestContextUtils.getLocale(request)) };

			}

		}
		return ViewUtils.DEFAULT_VIEW;
	}

}
